import asyncio
import queue
import time
import json
from datetime import datetime
from .websocket_module import WebSocketManager, listen_messages
from .interaction_module import UserInteraction
from .audio_playback_module import AudioPlayer
from .audio_processing_module import process_opus_audio, get_opus_available
from .recording_module import AudioRecorder, RECORDING_QUEUE
from .recording_processing_module import RecordingHandler

# 主模块：整合所有功能模块

# 创建音频队列 - 使用异步队列以提高性能
AUDIO_QUEUE = asyncio.Queue(maxsize=50)

# 全局变量
is_first_audio_packet = True

class XiaoZhiClient:
    def __init__(self):
        # 初始化各个模块
        self.websocket_manager = WebSocketManager()
        self.interaction = UserInteraction()
        self.audio_player = AudioPlayer(AUDIO_QUEUE)
        self.audio_recorder = AudioRecorder(RECORDING_QUEUE)
        self.recording_handler = RecordingHandler(RECORDING_QUEUE)
        
        # 设置交互模块的组件引用
        self.interaction.set_components(self.audio_player, self.recording_handler)
    
    # 创建所有任务
    async def create_tasks(self, websocket, audio_queue_callback, recording_queue_callback):
        tasks = []
        
        # 任务异常处理回调
        def task_done_callback(task):
            task_name = task.get_name()
            try:
                exc = task.exception()
                if exc:
                    print(f"\n[ERROR] 任务 '{task_name}' 抛出异常: {exc}")
                    import traceback
                    print("="*50)
                    traceback.print_exception(type(exc), exc, exc.__traceback__)
                    print("="*50)
                else:
                    print(f"[INFO] 任务 '{task_name}' 正常结束")
            except asyncio.CancelledError:
                print(f"[INFO] 任务 '{task_name}' 被取消")
            except Exception as e:
                print(f"[ERROR] 检查任务 '{task_name}' 状态时出错: {e}")
        
        # 启动心跳任务
        try:
            heartbeat_task = asyncio.create_task(self.websocket_manager.heartbeat(websocket), name="heartbeat")
            heartbeat_task.add_done_callback(task_done_callback)
            tasks.append(heartbeat_task)
        except Exception as e:
            print(f"[ERROR] 创建心跳任务失败: {e}")
        
        # 启动音频播放任务 - 使用优化后的异步版本
        try:
            audio_task = asyncio.create_task(self.audio_player.play_audio(), name="audio_playback")
            audio_task.add_done_callback(task_done_callback)
            tasks.append(audio_task)
        except Exception as e:
            print(f"[ERROR] 创建音频播放任务失败: {e}")
        
        # 启动录音任务，传入获取录音状态的函数
        try:
            record_task = asyncio.create_task(
                self.audio_recorder.record_audio(lambda: self.interaction.get_state()['is_recording']),
                name="audio_recording"
            )
            record_task.add_done_callback(task_done_callback)
            tasks.append(record_task)
        except Exception as e:
            print(f"[ERROR] 创建录音任务失败: {e}")
        
        # 启动消息监听任务，使用自定义的音频处理逻辑
        try:
            listen_task = asyncio.create_task(
                self.enhanced_listen_messages(websocket),
                name="message_listener"
            )
            listen_task.add_done_callback(task_done_callback)
            tasks.append(listen_task)
        except Exception as e:
            print(f"[ERROR] 创建消息监听任务失败: {e}")
        
        # 启动发送任务 - 这是用户交互的关键任务
        try:
            send_task = asyncio.create_task(
                self.interaction.send_messages(websocket),
                name="message_sender"
            )
            send_task.add_done_callback(task_done_callback)
            tasks.append(send_task)
            print(f"[DEBUG] 用户交互任务已创建: {send_task}")
        except Exception as e:
            print(f"[ERROR] 创建用户交互任务失败: {e}")
            import traceback
            traceback.print_exc()
        
        return tasks
    
    # 增强的消息监听函数，整合音频处理
    async def enhanced_listen_messages(self, websocket):
        global is_first_audio_packet
        audio_packet_count = 0
        consecutive_audio_blocks = 0
        last_audio_time = time.time()
        
        try:
            while True:
                current_time = time.time()
                
                # 接收消息（带超时）
                try:
                    message = await asyncio.wait_for(websocket.recv(), timeout=30.0)
                except asyncio.TimeoutError:
                    print("⏱️  接收消息超时，继续等待...")
                    continue
                
                # 处理不同类型的消息
                if isinstance(message, str):
                    # 文本消息处理
                    try:
                        data = json.loads(message)
                        print(f"收到文本消息: {data}")
                    except json.JSONDecodeError:
                        print(f"[ERROR] 无法解析JSON消息: {message}")
                else:
                    # 二进制消息处理（假设是Opus音频数据）
                    audio_packet_count += 1
                    last_audio_time = current_time
                    consecutive_audio_blocks += 1
                    
                    # 特殊处理第一个音频包
                    if is_first_audio_packet:
                        print("🎵 收到第一个音频包，开始播放...")
                        is_first_audio_packet = False
                    
                    # 解码Opus音频数据
                    pcm_data = process_opus_audio(message)
                    
                    # 将解码后的PCM数据放入队列
                    try:
                        AUDIO_QUEUE.put_nowait(pcm_data)
                    except queue.Full:
                        # print("[ERROR] 音频队列已满，丢弃部分数据")
                        # 尝试清理一个位置并添加新数据
                        try:
                            AUDIO_QUEUE.get_nowait()
                            AUDIO_QUEUE.task_done()
                            AUDIO_QUEUE.put_nowait(pcm_data)
                            # print("[OK] 已清理一个位置并添加新数据")
                        except Exception as put_e:
                            print(f"[ERROR] 将音频数据加入队列失败: {put_e}")
                
                # 检查是否有一段时间没有收到音频数据
                if current_time - last_audio_time > 5 and consecutive_audio_blocks > 0:
                    print(f"⏸️  音频流中断，已{current_time - last_audio_time:.1f}秒未收到音频数据")
                    consecutive_audio_blocks = 0
                    
        except Exception as e:
            print(f"❌ 监听出错: {e}")
            import traceback
            traceback.print_exc()
        finally:
            print(f"📋 监听任务结束 - 共接收 {audio_packet_count} 个音频包")
    
    # 运行客户端
    async def run(self):
        print("=== XiaoZhi Python 客户端启动 ===")
        print("[INIT] 初始化音频系统...")
        
        # 先进行音频播放测试
        audio_test_passed = self.audio_player.test_audio_playback()
        
        print("\n[INFO] 系统信息:")
        print(f"  - Opus解码可用: {'YES' if get_opus_available() else 'NO'}")
        print(f"  - 音频设备测试: {'PASSED' if audio_test_passed else 'FAILED'}")
        
        print("\n[NOTE] 提示:")
        print("1. 确保已安装所需库: pip install pyaudio opuslib==3.0.1 numpy websockets")
        print("2. 音频配置: 24kHz采样率, 单声道, 16位PCM格式")
        print("3. 即使Opus解码不可用，程序也会播放提示音表示收到音频数据")
        print("4. 按q退出程序")
        print("5. 按r开始/停止录音")
        print("======================================\n")
        
        # 启动WebSocket连接
        websocket = await self.websocket_manager.connect_websocket(
            audio_queue_callback=None,  # 暂时不需要，因为我们在enhanced_listen_messages中处理
            recording_queue_callback=None,
            return_websocket=True  # 修改为返回websocket实例
        )
        
        if websocket:
            # 创建并启动所有任务
            tasks = await self.create_tasks(websocket, None, None)
            
            print(f"\n[INFO] 已创建 {len(tasks)} 个任务")
            for task in tasks:
                print(f"  - {task.get_name()}")
            
            # 使用不同的方式来运行任务，让交互任务能够正常运行
            print("\n[INFO] 所有任务已启动，程序正在运行中...")
            
            # 由于用户交互任务需要等待输入，我们使用asyncio.gather来运行所有任务
            # 这样可以确保事件循环正确执行所有任务
            try:
                # 等待用户退出
                check_count = 0
                while not self.interaction.get_state()['user_initiated_exit']:
                    check_count += 1
                    
                    # 检查关键任务状态（忽略可能失败的录音任务）
                    critical_tasks = [
                        task for task in tasks 
                        if task.get_name() in ['message_sender', 'message_listener', 'heartbeat']
                    ]
                    
                    if critical_tasks:
                        critical_tasks_done = all(task.done() for task in critical_tasks)
                        if critical_tasks_done:
                            print("\n[WARN] 关键任务已完成，检查任务状态...")
                            for task in critical_tasks:
                                try:
                                    if task.done():
                                        exc = task.exception()
                                        if exc:
                                            print(f"  - {task.get_name()}: 失败 - {exc}")
                                        else:
                                            print(f"  - {task.get_name()}: 正常完成")
                                except Exception as e:
                                    print(f"  - {task.get_name()}: 无法获取状态 - {e}")
                            print("\n[ERROR] 关键任务异常退出，程序将终止")
                            break
                    
                    # 每30秒输出一次状态（避免刷屏）
                    if check_count % 60 == 0:
                        active_tasks = [t.get_name() for t in tasks if not t.done()]
                        print(f"[STATUS] 运行中的任务: {', '.join(active_tasks) if active_tasks else '无'}")
                    
                    await asyncio.sleep(0.5)  # 快速轮询以响应退出请求
                
                print("\n[INFO] 检测到用户退出请求，正在停止所有任务...")
                
            except KeyboardInterrupt:
                print("\n[INFO] 检测到键盘中断，正在停止所有任务...")
            finally:
                # 取消所有任务
                print("[INFO] 取消所有运行中的任务...")
                for task in tasks:
                    if not task.done():
                        task.cancel()
                        try:
                            await task
                        except asyncio.CancelledError:
                            pass
            
            # 尝试关闭WebSocket连接
            try:
                await websocket.close()
                print("[INFO] WebSocket连接已关闭")
            except Exception as e:
                print(f"[ERROR] 关闭WebSocket连接时出错: {e}")
            
            # 获取session_id
            session_id = self.websocket_manager.session_id
            return session_id
        else:
            print("[ERROR] WebSocket连接失败，无法启动任务")
            return None

# 主函数入口
def main():
    client = XiaoZhiClient()
    
    try:
        session_id = asyncio.run(client.run())
        print(f"[DONE] 所有操作完成, session_id: {session_id}")
    except KeyboardInterrupt:
        print("\n[EXIT] 程序已强制退出")
    except Exception as e:
        print(f"\n[ERROR] 程序运行出错: {e}")
        import traceback
        traceback.print_exc()
    finally:
        print("\n[END] 程序已结束")

if __name__ == "__main__":
    main()